#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Mikan Item Action

Mikan Python Web Framework
"""

__author__ = "K.Sonohara"
__status__ = "develop"
__version__ = "0.0.0_36"
__date__    = "2014/01/05"
__license__ = 'LGPL'

# ------------------------------------------------------------
## Import Section
# ------------------------------------------------------------
# Python
import traceback

# ESiPC
from esipc import ESiPCProperty
from esipc.mail import create_mail, send_mail

# Mikan
from mikan.idt.acidt import MIKAN_IDT_AC
from mikan.exception import MikanSendRedirectException, MikanExceptions, MikanStatusException
from mikan.action import AbstractMikanAction
from mikan.item.attribute import to_value

# ------------------------------------------------------------
## Variable Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Function Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Class Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class AbstractMikanItemAction(AbstractMikanAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request):
		super(AbstractMikanItemAction, self).__init__(request)

	def is_item_action(self):
		self.logger.debug(self.itemactionnumber)
		return self.request.get_param_str("item_action", None) != None

	def get_item_action_number(self):
		return self.request.get_param_str("item_action", None)

	def get_item_form(self):
		return None

	def get_item(self):
		return None

	def get_info_url(self):
		return "info?id=%s"

	def get_info_url_id(self):
		try:
			return self.item.id
		except:
			return None

	def send_redirect(self, url=None):
		u = None
		if url:
			u = url
		elif self.get_info_url_id():
			u = self.get_info_url() % self.get_info_url_id()
		else:
			u = "./"

		raise MikanSendRedirectException(self.request, str(u))

	# ----------------------------------------------------
	## Property
	item = ESiPCProperty(get_item, None, None)
	itemform = ESiPCProperty(get_item_form, None, None)
	isitemaction = ESiPCProperty(is_item_action, None, None)
	itemactionnumber = ESiPCProperty(get_item_action_number, None, None)
	infourl = ESiPCProperty(get_info_url, None, None)


# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemGetAction(AbstractMikanItemAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		super(MikanItemGetAction, self).__init__(request)

		self.FFormClass = formclass
		self.FEntityClass = entityclass
		self.FItem = None
		self.FItemForm = None

	def set_item_form(self, value):
		self.FItemForm = value

	def get_item_form(self):
		return self.FItemForm

	def set_item(self, value):
		self.FItem = value

	def get_item(self):
		return self.FItem

	def set_form_class(self, value):
		self.FFormClass = value

	def get_form_class(self):
		return self.FFormClass

	def set_entity_class(self, value):
		self.FEntityClass = value

	def get_entity_class(self):
		return self.FEntityClass

	def get_param_id(self):
		return self.request.get_param_str("id", None)

	def params(self):
		fields = self.itemform.sorted_fields()
		for field in fields:
			self.param(field, self.item)

	def param(self, field, item):
		if field.isvisibled and field.isenabled and (not field.isreadonly):
			#
			name = u"%s_%s" % ("item", field.itemname)
			paramvalue = None

			# debug
			if self.islogdebug:
				self.logger.debug(name)

			try:
				value = to_value(self.request.db, field.attribute, self.request.get_param_str(name, None), isdynamic=True)
				if value != None:
					paramvalue = value
				else:
#					if field.ispassword:
#						paramvalue = None
					paramvalue = item[field.itemname]
			except:
				self.logger.debug(name)
				self.logger.debug(traceback.format_exc())
				paramvalue = None

			# debug
			if self.islogdebug:
				self.logger.debug(paramvalue)

			# set
			try:
				if paramvalue != None:
					setattr(item, field.itemname, paramvalue)
			except:
				self.logger.debug(name)
				self.logger.debug(traceback.format_exc())

	def is_params(self):
		return False

	def init_item_form(self):
		# 検索
		pid = self.request.get_param_str("id", None)
		item = self.request.db.get(self.entityclass, pid)
		form = self.formclass(item)
		self.logger.debug(pid)
		self.logger.debug(form)
		self.logger.debug(item)

		# セット
		self.item = item
		self.itemform = form

	# ----------------------------------------------------
	## Prepare
	# @return True is chain prepare
	def prepare(self):

		self.init_item_form()

		# 情報取得
		if self.isparams:
			if self.isitemaction:
				self.params()
				self.logger.debug(self.item)

		# result & super
		return super(MikanItemGetAction, self).prepare()

	# ----------------------------------------------------
	## Property
	item = ESiPCProperty(get_item, set_item, None)
	entityclass = ESiPCProperty(get_entity_class, set_entity_class, None)
	itemform = ESiPCProperty(get_item_form, set_item_form, None)
	formclass = ESiPCProperty(get_form_class, set_form_class, None)
	isparams = ESiPCProperty(is_params, None, None)
	paramid = ESiPCProperty(get_param_id, None, None)

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemQueryAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		super(MikanItemQueryAction, self).__init__(request, formclass, entityclass)
		self.FItems = None

	def init_item_form(self):
		# 検索
		item = self.entityclass({})
		form = self.formclass(item)

		# セット
		self.item = item
		self.itemform = form

	def is_params(self):
		return True

	def set_items(self, value):
		self.FItems = value

	def get_items(self):
		return self.FItems

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		# 検索
		re = self.request.get_param_str("re", None)
		try:
			if re != None:
				self.item.values.update(self.request.usersession.values["re-%s" % re])
		except:
			if self.islogdebug:
				self.logger.debug(traceback.format_exc())

		if self.isitemaction:
			if self.islogdebug:
				self.logger.debug(self.itemactionnumber)

			# session save
			self.request.usersession.values["re-%s" % self.itemactionnumber] = self.item.export_values()

			# query
			items = self.request.db.query(self.entityclass, self.item)
			if len(items) > 0:
				self.items = items
				self.logger.debug(self.items)

		# result & super
		return super(MikanItemQueryAction, self).perform()

	# ----------------------------------------------------
	## Property
	items = ESiPCProperty(get_items, set_items, None)


# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemCreateAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		super(MikanItemCreateAction, self).__init__(request, formclass, entityclass)
		self.FItems = None

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self)

	def init_item_form(self):
		# 検索
		item = self.entityclass({})
		form = self.formclass(item)

		# セット
		self.item = item
		self.itemform = form

	def is_params(self):
		return True

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		# 検索
		if self.isitemaction:
			try:
				item = self.request.db.create(self.item)
				if item != None:
					self.item = item
					self.logger.debug(item)

			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemCreateAction, self).perform()

	# ----------------------------------------------------
	## Property

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemUpdateAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemUpdateAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self)

	def is_params(self):
		return True

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			try:
				self.request.db.update(self.item)
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemUpdateAction, self).perform()

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemCopyAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemCopyAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self)

	def is_params(self):
		return True

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			# copy
			try:
				self.item = self.request.db.copy(self.item)
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemCopyAction, self).perform()

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemRemoveAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemRemoveAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self, mlist=True)

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			try:
				self.request.db.remove(self.item)
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemRemoveAction, self).perform()

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemMailAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemMailAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemMailCoAction(self)
		MikanItemSendRedirectCoAction(self)

	# ----------------------------------------------------
	## Property

class MikanItemMailCoAction(AbstractMikanItemAction):

	# ----------------------------------------------------
	## Constructor
	#  @param parent Parent action
	def __init__(self, parent):
		# super
		super(MikanItemMailCoAction, self).__init__(parent)

	def get_item_form(self):
		try:
			return self.parent.itemform
		except:
			return None

	def get_item(self):
		try:
			return self.parent.item
		except:
			return None

	def get_title(self):
		fields = self.itemform.sorted_fields()

		try:
			title = None
			for field in fields:
				if field.isvisibled:
					break
			title = self.item[field.itemname]
			if title != None:
				return u" %s [%s]" % (self.itemform.itemcaption, title)
		except:
			pass
		return u" %s" % (self.itemform.itemcaption)

	def get_mail_text(self, item, form):
		return self.request.db.export("text", item, form)

	def get_mail_title(self, item, form):
		return self.title

	def get_mail_to(self, item, form):
		return self.request.get_param_str("mailto", "root@localhost")

	def get_mail_from(self, item, form):
		return self.request.usermail

	def send_mail(self, mailfrom, mailto, mail, host=None):
		send_mail(mailfrom, mailto, mail, None)

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			try:
				# mail param
				mailto = self.get_mail_to(self.item, self.itemform)
				mailfrom = self.get_mail_from(self.item, self.itemform)
				mailtitle = self.get_mail_title(self.item, self.itemform)
				mailtext = self.get_mail_text(self.item, self.itemform)

				# create mail
				mail = create_mail(mailtitle, mailtext, mailfrom, mailto, encode="UTF-8")

				# log
				if self.islogdebug:
					self.logger.debug(mail)

				# send mail
				if self.request.maildryrun == "0":
					self.send_mail(mailfrom, mailto, mail, host=self.request.mailsmtphost)
				else:
					self.logger.error(unicode(mail))
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemMailCoAction, self).perform()

	# ----------------------------------------------------
	## Property
	title = ESiPCProperty(get_title, None, None)

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemSequenceUpAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemSequenceUpAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self)

	def is_params(self):
		return True

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			try:
				self.item = self.request.db.sequence_up(self.item)
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemSequenceUpAction, self).perform()

# ------------------------------------------------------------
## Mikan アクション 抽象 クラス
#
class MikanItemSequenceRemoveAction(MikanItemGetAction):

	# ----------------------------------------------------
	## Constructor
	#  @param request Request
	#  @param formclass Item form class
	#  @param entityclass Item entity class
	def __init__(self, request, formclass, entityclass):
		# super
		super(MikanItemSequenceRemoveAction, self).__init__(request, formclass, entityclass)

		# coaction
		MikanItemCommitCoAction(self)
		MikanItemSendRedirectCoAction(self, mlist=True)

	def is_params(self):
		return True

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			# remove
			try:
				self.item = self.request.db.sequence_remove(self.item)
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

		# result & super
		return super(MikanItemSequenceRemoveAction, self).perform()

# ------------------------------------------------------------
## Mikan Item Send Redirect Action Class
#
class MikanItemSendRedirectCoAction(AbstractMikanItemAction):

	# ----------------------------------------------------
	## Constructor
	#  @param parent Parent action
	#  @param list True is send URL list
	def __init__(self, parent, mlist=False):
		# super
		super(MikanItemSendRedirectCoAction, self).__init__(parent)

		self.FList = mlist

		# sort
		self.sortkey = 9999

	def get_url(self):
		return None

	def is_list(self):
		return self.FList

	def get_item_form(self):
		try:
			return self.parent.itemform
		except:
			return None

	def get_item(self):
		try:
			return self.parent.item
		except:
			return None

	def get_info_url_id(self):
		if self.islist:
			return None
		else:
			return super(MikanItemSendRedirectCoAction, self).get_info_url_id()

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			# send redirect
			if len(self.request.exceptions) == 0:
				self.send_redirect(self.get_url())

		# result & super
		return super(MikanItemSendRedirectCoAction, self).perform()

	# ----------------------------------------------------
	## Property
	islist = ESiPCProperty(is_list, None, None)

# ------------------------------------------------------------
## Mikan Item Commit Action Class
#
class MikanItemCommitCoAction(AbstractMikanItemAction):

	# ----------------------------------------------------
	## Constructor
	#  @param parent Parent action
	def __init__(self, parent):
		# super
		super(MikanItemCommitCoAction, self).__init__(parent)

		# sort
		self.sortkey = 1000

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if self.isitemaction:
			# commit
			try:
				if len(self.request.exceptions) == 0:
					self.request.db.commit()
			except Exception, e:
				if self.islogdebug:
					self.logger.debug(traceback.format_exc())
				if isinstance(e, MikanExceptions):
					self.request.exceptions.extend(e.exceptions)
				else:
					self.request.exceptions.append(e)

			# find exception is rollback
			if len(self.request.exceptions) == 0:
				try:
					self.request.db.rollback()
				except Exception, e:
					self.logger.debug(traceback.format_exc())

		# result & super
		return super(MikanItemCommitCoAction, self).perform()

# ------------------------------------------------------------
## Mikan Item Access Control Action Class
#
class MikanItemAccessControlCoAction(AbstractMikanItemAction):

	def get_item_form(self):
		try:
			return self.parent.itemform
		except:
			return None

	def get_item(self):
		try:
			return self.parent.item
		except:
			return None

	def get_can_ac(self):
		return MIKAN_IDT_AC.AC_READ

	def get_ac(self):
		return "FFFF"

	def get_ac_number(self):
		if self.request.issa:
			return 0
		return 3

	# ----------------------------------------------------
	## Constructor
	#  @param parent Parent action
	def __init__(self, parent):
		# super
		super(MikanItemAccessControlCoAction, self).__init__(parent)

		# sort
		self.sortkey = -1000

	# ----------------------------------------------------
	## Perform
	# @return True is chain perform
	def perform(self):
		if not self.request.db.ac(self.canac, self.acnumber, self.ac):
			# TODO アクセス権エラー例外
			raise MikanStatusException(self.request, 403)

		# result & super
		return super(MikanItemAccessControlCoAction, self).perform()

	# ----------------------------------------------------
	## Property
	ac = ESiPCProperty(get_ac, None, None)
	canac = ESiPCProperty(get_can_ac, None, None)
	acnumber = ESiPCProperty(get_ac_number, None, None)

# ------------------------------------------------------------
## Main Section
# ------------------------------------------------------------
if __name__ == '__main__':
	pass

# ------------------------------------------------------------
